/*
 * \brief  Thread interface
 * \author Norman Feske
 * \date   2006-04-28
 */

/*
 * Copyright (C) 2006-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__BASE__THREAD_H_
#define _INCLUDE__BASE__THREAD_H_

#include <cpu_session/cpu_session.h>
#include <base/lock.h>
#include <base/stdint.h>
#include <base/native_types.h>

namespace Genode {

	/**
	 * Thread_base provides the functionality to start the
	 * execution of an activity.
	 */
	class Thread_base
	{
		protected:

			/**
			 * Capability for this thread (set by _start())
			 */
			Genode::Thread_capability _thread_cap;

			/**
			 * Physical thread ID
			 */
			Native_thread _tid;

			/**
			 * Start execution of thread at entry function
			 *
			 * \param sp    initial stack pointer
			 * \param name  name of thread (used for debugging)
			 *
			 * This function should be called from the constructor
			 * of the derived class.
			 */
			void _start(void *sp, const char *name = "<noname>");

			/**
			 * Helper function for entering the entry() function
			 *
			 * We require this static function to pass its function pointer
			 * to the pthread_create call in the _start() funcion. On thread
			 * startup, we first block at the start lock, which must be
			 * released by the thread creator via the go() function.
			 */
			static void _thread_start(void *arg);

			/**
			 * Thread startup argument frame
			 */
			static Lock         _startup_arg_lock;
			static Thread_base *_startup_arg;

		public:

			virtual ~Thread_base();

			/**
			 * Entry function of the thread
			 */
			virtual void entry() = 0;

			/**
			 * Cancel currently blocking operation
			 */
			void cancel_blocking();

			/**
			 * Only to be called from platform-specific code
			 */
			Native_thread tid() { return _tid; }
	};


	template <unsigned STACK_SIZE>
	class Thread : public Thread_base
	{
		protected:

			const char *_name;  /* thread name (for debugging) */
			char _stack[STACK_SIZE];

		public:

			/**
			 * Constructor
			 *
			 * \param name  thread name (for debugging)
			 */
			explicit Thread(const char *name = "<noname>"): _name(name) { }

			/**
			 * Start execution of the thread
			 */
			void start() { _start(&_stack[STACK_SIZE - sizeof(umword_t)], _name); }
	};
}

#endif /* _INCLUDE__BASE__THREAD_H_ */
